/*
 * Copyright 2010 Alexander Ulizko
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.ulizko.template.soy.javaSrc;

import com.ulizko.template.soy.utils.MainUtils;
import com.ulizko.template.soy.utils.StringUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.inject.Injector;
import com.google.template.soy.SoyFileSet;
import com.google.template.soy.javasrc.SoyJavaSrcOptions;
import com.google.template.soy.msgs.SoyMsgBundle;
import com.google.template.soy.msgs.SoyMsgBundleHandler;
import com.google.template.soy.shared.SoyGeneralOptions;
import com.google.template.soy.xliffmsgplugin.XliffMsgPluginModule;

import java.io.File;
import java.io.IOException;
import java.util.Map;

/**
 * @author Alexander <alexander@ulizko.com> Ulizko
 */
public class SoyFileSetBuilder {


    private SoyJavaSrcOptions javaSrcOptions = new SoyJavaSrcOptions();
    /**
     * The path to the translated messages file. If not provided, messages from
     * the Soy source are used.
     */
    private String messageFilePath = "";

    /**
     * The scheme to use for handling 'css' commands. Specifying 'literal' will
     * cause command text to be inserted as literal text. Specifying 'reference'
     * will cause command text to be evaluated as a data or global reference. This
     * option has no effect if the Soy code does not contain 'css' commands.
     */
    private SoyGeneralOptions.CssHandlingScheme cssHandlingScheme = SoyGeneralOptions.CssHandlingScheme.LITERAL;

    /**
     * The path to a file containing the mappings for global names to be substituted
     * at compile time. Each line of the file should have the format
     * "<global_name> = <primitive_data>" where primitive_data is a valid Soy
     * expression literal for a primitive type (null, boolean, integer, float, or
     * string). Empty lines and lines beginning with "//" are ignored. The file
     * should be encoded in UTF-8. If you need to generate a file in this format
     * from Java, consider using the utility
     * SoyUtils.generateCompileTimeGlobalsFile().
     */
    private String compileTimeGlobalsFile = "";

    /**
     * Specifies the full class name of a Guice module that binds a SoyMsgPlugin.
     * If not specified, the default is
     * com.google.template.soy.xliffmsgplugin.XliffMsgPluginModule, which binds
     * the XliffMsgPlugin.
     */
    private String messagePluginModule = XliffMsgPluginModule.class.getName();

    /**
     * Java package name for soy info classes;
     */
    private String javaPackageName;

    /**
     *
     */
    private String javaClassNameSource = "filename";

    /**
     * Specifies the full class names of Guice modules for function plugins and
     * print directive plugins (comma-delimited list).
     */
    private String pluginModules = "";
    private SoyFileSet soyFileSet;
    private Injector injector;


    public void buildSoyFileSet(ImmutableList<String> soyFiles) throws IOException {
        injector = MainUtils.createInjector(messagePluginModule, pluginModules);

        SoyFileSet.Builder sfsBuilder = new SoyFileSet.Builder();
        sfsBuilder.setCssHandlingScheme(cssHandlingScheme);

        if (compileTimeGlobalsFile.length() > 0) {
            sfsBuilder.setCompileTimeGlobals(new File(compileTimeGlobalsFile));
        }

        // add input files to builder
        for (String pathToFile : soyFiles) {
            sfsBuilder.add(new File(pathToFile));
        }

        soyFileSet = sfsBuilder.build();
    }

    /**
     * Generates java source from provided soy files.
     *
     * @return Generated Java Source. Looks like a big ugly blob.
     * @throws java.io.IOException      Exception bubbled from SoyToJavaSrcCompilerExperimental
     */
    public String compileToJavaSrc() throws IOException {
        // Creat SoyMsgBundle
        SoyMsgBundle msgBundle = null;

        if (messageFilePath.length() > 0) {
            SoyMsgBundleHandler msgBundleHandler = injector.getInstance(SoyMsgBundleHandler.class);
            msgBundle = msgBundleHandler.createFromFile(new File(messageFilePath));
        }

        return soyFileSet.compileToJavaSrc(javaSrcOptions, msgBundle);
    }

    /**
     * Generates SoyInfo (ParseInfo) from provided soy files.
     * @return Map\<ClassName, ClassSource\> of SoyInfo files.
     * @throws IllegalArgumentException If there is no valid java package name for Soy Info files provided,
     * or if there is no valid javaClassNameSource provided.
     */
    public Map<String, String> generateParseInfo() throws IllegalArgumentException {
        Preconditions.checkArgument(javaPackageName.length() > 0, "must provide java package name for SoyInfo files generation");
        Preconditions.checkArgument(StringUtils.isValidPackageName(javaPackageName), "%s is not a valid java package", javaPackageName);
        Preconditions.checkArgument(javaClassNameSource.length() > 0, "javaClassNameSource must be one of \"filename\", \"namespace\", \"generic\"");

        return soyFileSet.generateParseInfo(javaPackageName, javaClassNameSource);
    }

    public String getMessageFilePath() {
        return messageFilePath;
    }

    public void setMessageFilePath(String messageFilePath) {
        this.messageFilePath = messageFilePath;
    }

    public SoyGeneralOptions.CssHandlingScheme getCssHandlingScheme() {
        return cssHandlingScheme;
    }

    public void setCssHandlingScheme(SoyGeneralOptions.CssHandlingScheme cssHandlingScheme) {
        this.cssHandlingScheme = cssHandlingScheme;
    }

    public String getCompileTimeGlobalsFile() {
        return compileTimeGlobalsFile;
    }

    public void setCompileTimeGlobalsFile(String compileTimeGlobalsFile) {
        this.compileTimeGlobalsFile = compileTimeGlobalsFile;
    }

    public String getMessagePluginModule() {
        return messagePluginModule;
    }

    public void setMessagePluginModule(String messagePluginModule) {
        this.messagePluginModule = messagePluginModule;
    }

    public String getPluginModules() {
        return pluginModules;
    }

    public void setPluginModules(String pluginModules) {
        this.pluginModules = pluginModules;
    }

    public SoyJavaSrcOptions getJavaSrcOptions() {
        return javaSrcOptions;
    }

    public void setJavaSrcOptions(SoyJavaSrcOptions javaSrcOptions) {
        this.javaSrcOptions = javaSrcOptions;
    }

    public String getJavaPackageName() {
        return javaPackageName;
    }

    public void setJavaPackageName(String javaPackageName) {
        this.javaPackageName = javaPackageName;
    }

    public SoyFileSet getSoyFileSet() {
        return soyFileSet;
    }

    public void setSoyFileSet(SoyFileSet soyFileSet) {
        this.soyFileSet = soyFileSet;
    }

    public String getJavaClassNameSource() {
        return javaClassNameSource;
    }

    public void setJavaClassNameSource(String javaClassNameSource) {
        this.javaClassNameSource = javaClassNameSource;
    }
}
